/* 
 * UCLA CS 111 - Fall 2007 - Lab 1
 * Skeleton code for commandline parsing for Lab 1 - Shell processing
 * This file contains skeleton code for parsing input from the commandline.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#include "cmdline.h"



int isSpecialChar(char ch)
{
  switch(ch)
    {
    case '(':
    case ')':
    case ';':
    case '|':
    case '&':
    case '>':
    case '<':
      return 1;
    default:
      return 0;
    }
}




void processString(char* input_line, char* output_buffer)
{
  // For extra-credit: insert ' ' in the string so the pre-existing code will work
  char* post_string = output_buffer;
  char* pre_process = input_line;
  size_t sizeofstring = 0;
  
  
  // Figure out the size of the current string
  sizeofstring = strlen(input_line);
 
 size_t MAX_SIZE = sizeofstring * 2 + 1;

  // Copy input_line to post_process
  //  strcpy(input_line, post_process);
  size_t i;


  /************** Process post_process ******************
   * Meaning: add spaces to all the special characters   
   *
   * NOTE: pre_process is smaller than MAX_SIZE
  *****************************************************/
 
  char lastChar = '\0';
  char* post_process = post_string;
  int double_char_token;
  int in_quotes = 0;
  
  for(i = 0 ; *pre_process !='\0' && i < MAX_SIZE - 1; i++)    // -1 to include the zero byte
    {
      double_char_token = 0;
     
      
      if(in_quotes == 0 && (*pre_process == '\"' || *pre_process == '\''))
	in_quotes = 1;
      else if(in_quotes == 1 && (*pre_process == '\"' || *pre_process == '\''))
	in_quotes = 0;

      // if the character is special, add a space BEFORE* AND AFTER IT.
      // otherwise just copy the character
      
      
      if(isSpecialChar(*pre_process) > 0 && in_quotes == 0){
	
	// check if we have the pattern *_2> (* = any non symbol, _ = space)
	if(*pre_process == '>' && (i >= 3) && (*(pre_process-1) == '2') && (*(pre_process-2) == ' ') && (isSpecialChar(*(pre_process-3)) == 0 ))
	  {
	    *post_process = *pre_process;
	    pre_process++;
	    post_process++;
	    continue;
	  }
	
	// check if we have a double character token (|| or &&), these are handled differently 
	if(i+1 < MAX_SIZE-1 && (*pre_process == '&' || *pre_process == '|') && (*(pre_process + 1) == *pre_process))
	  double_char_token = 1;
      
	// * for the space BEFORE, check to see if there already exists a space. 
	//   if so, then don't add a space.
	if(i > 0 && *(post_process-1) == ' '){
	  //*post_process++; // skip adding whitespace
	} else
	  *post_process++ = ' ';
	
	if(double_char_token > 0){
	  // copy the next char to post_process
	  *post_process++ = *pre_process++;
	  *post_process++ = *pre_process;
	} else *post_process++ = *pre_process; 

	  *post_process = ' ';

      }else *post_process = *pre_process;
      
 
     
     
      pre_process++;
      post_process++;
    }

  // add the zero byte add the end
  // WORST-CASE: this is puts it at the last char position of post_string[MAX_SIZE  - 1]
  *(++post_process) = '\0';    
  


}

/* 
 * Main function for testing commandline parsing.
 */
int
main(int argc, char *argv[])
{
	// String used to store the shell input
	char input_buffer[BUFSIZ];

	// Ignore our arguments
	(void) argc, (void) argv;
	
	while (1) {
		parsestate_t parsestate;
		command_t *cmdlist;
		// Print the prompt, and make sure it gets to the screen
		// right away
		printf("cs111_fall07$ ");
		fflush(stdout);
		
		// Read a string, checking for error or EOF
		if (fgets(input_buffer, BUFSIZ, stdin) == NULL) {
			if (ferror(stdin))
				// This function prints a description of the
				// error, preceded by 'cs111_fall07: '.
				perror("cs111_fall07");
			break;
		}
		
		/**** Do some preprocessing work on input_buffer ******/

		
		// Create a new string with a bigger capacity
		size_t sizeofstring = 0;
  
  
		// Figure out the size of the current string
		sizeofstring = strlen(input_buffer);
 

		size_t MAX_SIZE = sizeofstring * 2 + 1;
		char* post_string = (char*) malloc(MAX_SIZE);
 
		post_string[0] = '\0';


		 processString(input_buffer, post_string);
		
	
		parse_init(&parsestate, post_string);
		cmdlist = command_line_parse(&parsestate, 0);
		
		if(sizeofstring == 1 && !cmdlist && post_string[0] == '\n') {
		  // This is an empty command, must build it
		  cmdlist = command_alloc();
		  cmdlist->controlop = TOK_END;

		}
		
		if (!cmdlist)
			fprintf(stderr, "Syntax error\n");
	
		  
		// Print the command
		command_print(cmdlist, 0);
		command_free(cmdlist);
		
		free(post_string);
	}

	printf("\n");
	return 0;
}
